/*
 *  Copyright (C) 1993  Robert Davis
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of Version 2, or any later version, of 
 *  the GNU General Public License as published by the Free Software 
 *  Foundation.
 */


static char RCSId[]="$Id: DataPane.m,v 1.13 1993/05/18 03:54:59 davis Exp $";


#import <appkit/Application.h>
#import <appkit/Box.h>
#import <appkit/Form.h>
#import <appkit/OpenPanel.h>
#import <appkit/View.h>

#import <sys/param.h>			/* MAXPATHLEN                   */

#import "CellScrollView.h"
#import "DataOptionsPanel.h"
#import "DataPane.h"
#import "FunctionObject.h"
#import "EditMatrix.h"
#import "GnuplotPlot.h"
#import "Status.h"
#import "SubCell.h"


@interface DataPane (Private)

- _updateFunctionsMatrix;
- _updateControlsForSelectedFunction;

@end


@implementation DataPane


- init
{
    [super init];

    [NXApp loadNibSection: "DataPane.nib"
		    owner: self
		withNames: NO
		 fromZone: [self zone]];

    icon = "InspectorData.tiff";

    /*  Initialize the CellScrollView of functions  */

    [functionsScrollView initMatrixCellClass:[SubCell class] cols:1];
    functionsMatrix = [functionsScrollView cellMatrix];
    [[functionsMatrix setAction:@selector(selectFunction:)] setTarget:self];

    return self;
}


- free
{
    [optionsPanel free];
    return [super free];
}


/*  
 *  Overridden from Pane.
 */
- selectControl:sender
{
    [functionsForm selectTextAt:0];
    return self;
}


- (BOOL)updateStatus:aStatus doc:aDoc
{
    id		oldStatus = status;

    /*  
     *  We only bother updating if status has changed since we last 
     *  updated, or if we just became the current pane (didSwap) -- 
     *  assuming that status and aDoc are non-nil, of course.
     */

    if ([super updateStatus:aStatus doc:aDoc]
	&& ((status != oldStatus) || didSwap)) {

	Window *viewWindow;

	[(viewWindow = [view window]) disableDisplay];

	functionObjects = [status functions];

	[dummyFormCellX setStringValue:[status dummyVar:X_TAG]];
	[dummyFormCellY setStringValue:[status dummyVar:Y_TAG]];
	[dummyFormCellY setEnabled:[status isThreeD]];
	[self _updateFunctionsMatrix];

	if (![functionsMatrix selectedCell]
	    && ![functionsMatrix multipleCellsSelected])

	    [functionsMatrix selectCellAt:0:0];		/* Make a selection */


	[self _updateControlsForSelectedFunction];

	[viewWindow reenableDisplay];

	[self perform:@selector(selectControl:)
		 with:self
	   afterDelay:1
       cancelPrevious:YES];

	didSwap = NO;
	[optionsPanel ownerDidSwapIn:self];	/* We're done swapping now */
	return YES;

    }

    return NO;
}


- (BOOL)forceUpdateStatus:aStatus doc:aDoc
{
    BOOL	needsRedisplay;

    /*  
     *  Must update ourself first, then update the options panel 
     *  because the options panel may look at our controls, etc. to 
     *  update itself.
     */
    needsRedisplay = [super forceUpdateStatus:aStatus doc:aDoc];

    if ([[optionsPanel panel] isVisible])
	[optionsPanel forceUpdate];

    return needsRedisplay;
}



- didSwapIn:sender
{
    [super didSwapIn:sender];
    didSwap = YES;
    return self;
}



- didSwapOut:sender
{
    [super didSwapOut:sender];
    [optionsPanel ownerDidSwapOut:self];
    return self;
}



- doSetDummy:sender
{
    [status setDummyVar:[sender tag] to:[sender stringValue]];
    return self;
}


- findDataFile:sender
{
    const char *const *files;
    id openPanel;
    char fullName[MAXPATHLEN];

    openPanel = [[OpenPanel new] allowMultipleFiles:YES];
    [openPanel setTitle:"Add Data File"];

    if ([openPanel runModalForTypes:NULL])
        for (files = [openPanel filenames]; files && *files; files++) {

            sprintf (fullName, "%s/%s", [openPanel directory], *files);
            [self addDataFile:fullName];

        }

    return self;
}


- selectFunction:sender
{
    if (![functionsMatrix selectedCell]
	&& ![functionsMatrix multipleCellsSelected]) {

	[functionsMatrix selectCellAt:0:0];
	[self _updateControlsForSelectedFunction];

    } else {
	[self _updateControlsForSelectedFunction];
	[functionsForm selectTextAt:0];
    }

    [optionsPanel forceUpdate];

    return self;
}


- deleteSelectedFunctions:sender
{
    int i;
    int maxrow = [functionsMatrix cellCount] - 1;
    int row = maxrow;
    BOOL gotRow = NO;
    int col = [functionsMatrix selectedCol];

    for (i = maxrow; i >= 0; i--) {
        SubCell *cell = [functionsMatrix cellAt:i:0];
        if ([cell isHighlighted]) {
            /*
             * If a cell is highlighted, remove (and free) the corresponding
             * item from the list of SubObjects.
             */
            [[functionObjects removeObject:[cell subObject]] free];
	    if (!gotRow) {
		row = (i == maxrow)? i - 1: i;
		gotRow = YES;
	    } else
		row--;
        }
    }

    [functionsScrollView loadCol:0 from:functionObjects];

    [functionsMatrix selectCellAt: row:col];
    [functionsMatrix scrollCellToVisible: row:col];
    [self selectFunction:self];

    /*  
     *  We change the list of functions maintainted by Status without 
     *  going through Status, so we need to make sure the changes are 
     *  noticed. 
     */
    [status reportSettingsChange:self];

    return self;
}


- modifySelectedFunction:sender
{
    id cell = [functionsMatrix selectedCell];

    [[cell subObject] setStringValue: [functionsForm stringValue]];
    [functionsScrollView loadCol:0 from:functionObjects];
    [functionsMatrix selectCell:cell];
    [self selectFunction:self];

    [status reportSettingsChange:self];
    return self;
}


- addFunction:sender
{
    const char *stringValue;
    int count;
    FunctionObject *functionObject;

    stringValue = [functionsForm stringValue];

    if (![FunctionObject isAcceptableStringValue:stringValue])  {
        [self selectFunction:self];
        return nil;
    }

    functionObject = [[FunctionObject allocFromZone: [status zone]]
                                     initFromString: stringValue
					   isThreeD: [status isThreeD]];
    [functionObjects addObject:functionObject];
    [functionsScrollView loadCol:0 from:functionObjects];
  /*
   *  Assumptions in this next line:
   *    There are as many SubCells as there are functionObjects
   *    We've added the new functionObject at the end of the list.
   *    We want to display the functionObject we just added and highlight it.
   *  In short, this is a hack.
   *                                    -- CellScrollView, NeXT Example
   */
    count = [functionObjects count] - 1;
    [functionsMatrix scrollCellToVisible:count :0];
    [functionsMatrix selectCellAt:count:0];
    [self selectFunction:self];

    [status reportSettingsChange:self];

    return self;
}



- functionsMatrix
{
    return functionsMatrix;
}



- addDataFile:(const char *)aPath
{
    int count;

    [doc addDataFile:aPath];
    [functionsScrollView loadCol:0 from:functionObjects];

    /*
     * Assumptions in this next line:
     *    There are as many SubCells as there are functionObjects
     *    We've added the new functionObject at the end of the list.
     *    We want to display the functionObject we just added and highlight it.
     * In short, this is a hack.
     *                          -- CellScrollView, NeXT Example
     */
    count = [functionObjects count] - 1;
    [functionsMatrix scrollCellToVisible:count :0];
    [functionsMatrix selectCellAt:count:0];
    [self selectFunction:self];

    return self;
}


- showOptionsPanel:sender
{
    if (!optionsPanel) {
	optionsPanel = [[DataOptionsPanel allocFromZone:[self zone]] init];
	[optionsPanel setOwner:self];
    }
    [optionsPanel showPanel:self];
    return self;
}



// Shuts up the compiler about unused RCSId
- (const char *) rcsid
{
    return RCSId;
}


@end


@implementation DataPane (Private)


- _updateFunctionsMatrix
{
    int functionCount, counter = 0;
    int fieldcount;
    int row = [functionsMatrix selectedRow];
    int col = [functionsMatrix selectedCol];

    [functionsScrollView loadCol:0 from:functionObjects];
    if (functionCount = [functionObjects count]) {
        for (counter = 0; counter < functionCount; counter++)
            [[functionsMatrix cellAt:counter:0]
                             setStringValue:[[functionObjects objectAt:counter]
                                             stringValue]];
    }

    fieldcount = [functionsMatrix cellCount];
    while (counter < fieldcount)
        [[functionsMatrix cellAt:counter++:0] setStringValue:""];

    [functionsMatrix selectCellAt:(row > fieldcount)? fieldcount:row :col];

    return self;
}


- _updateControlsForSelectedFunction
{
    id	singleCell = [functionsMatrix selectedCell];
    BOOL enabled = (singleCell || [functionsMatrix multipleCellsSelected]);

    if (singleCell)
	[functionsForm setStringValue:[[singleCell subObject] stringValue]];
    else if (enabled)
	[functionsForm setStringValue:""];

    [inspectButton setEnabled:enabled];
    [deleteFunctionButton setEnabled:enabled];
    [modifyFunctionButton setEnabled:singleCell? YES:NO];

    return self;
}


@end
